/*
    This file is part of Posixcpp library.

    Posixcpp library is free software: you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public License
    as published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Posixcpp library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU LesserGeneral Public
    License along with Posixcpp library. If not, see
    <http://www.gnu.org/licenses/>.
 */

/**
 * @file posix_thread.hpp
 * @brief POSIX Thread and related datatypes header
 */

#ifndef POSIX_THREADS_THREAD_INCLUDED
#define POSIX_THREADS_THREAD_INCLUDED

#include <ostream>

#include "posix_threads.hpp"
#include "posixcpp_activeobject.hpp"

namespace posix {
namespace threads {

/**
 * @class Thread
 * @brief Class, representing thread of execution
 */
class Thread : public posixcpp::ActiveObject {
public:
    /**
     * @class Attributes
     * @brief Thread creation attributes
     *
     * Can be used to create multiple threads with same
     * parameters
     */
    class Attributes final
    {
    public:
        Attributes();
        ~Attributes();

        /**
         * @property handle
         * @brief pthread handle for attributes
         */

        /**
         * @brief handle property get
         */
        pthread_attr_t & handle() {
            return m_handle;
        }
        /**
         * @brief handle property constant get
         */
        const pthread_attr_t & handle() const {
            return m_handle;
        }

        /**
         * @property schedPolicy
         * @brief OS scheduling policy for the thread
         */

        /**
         * @brief schedPolicy propery get
         */
        SchedulerPolicy_t schedPolicy() const;
        /**
         * @brief schedPolicy propery set
         */
        void setSchedPolicy(SchedulerPolicy_t newVal);

        /**
         * @property schedParam
         * @brief Scheduler parameters (priority) for the thread
         */

        /**
         * @brief schedParam property get
         */
        int schedParam() const;
        /**
         * @brief schedParam property set
         */
        void setSchedParam(int priority);

        /**
         * @property inheritSched
         * @brief Scheduler inheritance mode for the thread
         */

        /**
         * @brief inheritSched property get
         */
        SchedulerInheritance_t inheritSched() const;
        /**
         * @brief inheritSched property set
         */
        void setInheritSched(SchedulerInheritance_t newVal);

    private:
        /**
         * POSIX thread attributes handle
         */
        pthread_attr_t m_handle;
    };

    /**
     * @brief Thread function pointer
     */
    typedef void * (*ThreadFunction_t)(void*);
    /**
     * @brief Constructor
     *
     * @param function Function of type ThreadFunction_t that will be executed by the thread,
     * @param param Thread function parameter.
     */
    Thread(
      ThreadFunction_t function,
      void* param );
    /*
     * @brief Constructor
     * 
     * @param handle native pthreads handle for existing thread
     */
    Thread(pthread_t & handle);
    /**
     * @brief d-tor
     */
    virtual ~Thread();
    /**
     * @brief Get thread object of current running thread
     */
    static Thread self();
    /**
     * @brief Start thread
     */
    void start();
    /**
     * @brief Join with thread
     */
    void * join();

    posixcpp::ActiveObject::ExecutionsRes_t waitFinish() override;

    /**
     * @brief Detach thread ( join never will be called )
     */
    void detach();
    /**
     * @brief Cancel thread
     */
    void cancel();

    /**
     * @brief Set attributes which will be used to start thread
     */
    void setAttributes(const Attributes* newVal) {
        m_attributes = newVal;
    }
    
    /**
     * @property function
     * 
     * C function (or C++ class static member function), wich will be
     * executed in the started thread. NULL means that the run() method
     * of the instance should be executed
     */
    
    ThreadFunction_t function() const {
        return m_function;
    }
    void setFunction(ThreadFunction_t func) {
        m_function = func;
    }

    /**
     * @property schedPolicy
     * @brief OS Scheduler policy for sthe thread
     */

    /**
     * @brief get schedPolicy
     */
    SchedulerPolicy_t schedPolicy();
    /**
     * @brief set schedPolicy
     */
    void setSchedPolicy(SchedulerPolicy_t newVal);

    /**
     * @property cancelState
     * @brief cancel state of the current thread
     */

    /**
     * @brief get cancelState
     */
    static CancelState_t cancelState();
    /**
     * @brief set cancelState
     */
    static void setCancelState(CancelState_t state);

    /**
     * @property cancelType
     */

    /**
     * @brief get cancelType
     */
    static CancelType_t cancelType();
    /**
     * @brief set cancelType
     */
    static void setCancelType(CancelType_t newType);

    /**
     * @property schedParam
     */

    /**
     * @brief get schedParam
     */
    SchedulerParameters_t schedParam();
    /**
     * @brief set schedParam
     */
    void setSchedParam(SchedulerParameters_t newVal);

    /**
     * @brief Test if there was pending cancelation request
     */
    static void testCancel();
    /**
     * @brief Yield the CPU to another thread
     */
    static void yield();
    /**
     * @brief Exit current thread
     */
    static void exit(void * retVal = NULL);
protected:
    /**
     * @brief Default constructor
     *
     * Starts instance run() method, therefore should be only used by inherited classes
     */
    Thread();

private:
    /**
     * Thread function
     *
     * @param args Must be the valid Thread object pointer
     */
    static void* _threadStart(void* args);
    /**
     * POSIX threads manipulator
     */
    pthread_t m_handle;
    /**
     * Thread function pointer
     */
    ThreadFunction_t m_function;
    /**
     * Thread function parameter
     */
    void* m_functionParameter;
    /**
     * Thread creation attributes
     */
    const Attributes * m_attributes;
};

}
}
#endif // POSIX_THREADS_THREAD_INCLUDED
